#ifndef BLOCKINGQUEUE_H
#define BLOCKINGQUEUE_H

#include <mutex>
#include <condition_variable>
#include <deque>

/*
 普通guard为std::lock_guard
 c++11的条件变量需要配合std::unique_lock
 */
template <typename T>
class BlockingQueue
{
public:
    BlockingQueue()
        : m_mutex()
        , notEmpty()
        , queue()
    {
    }
    ~BlockingQueue()
    {};

    void enqueue(const T& t)
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        queue.push_back(t);
        notEmpty.notify_one();
    }

    void enqueue(T&& t)
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        queue.push_back(std::move(t));
        notEmpty.notify_one();
    }

    T dequeue()
    {
        //    std::unique_lock<std::mutex> lock(m_mutex);
        //    m_cond.wait(lock, [&](){return !queue.empty();});

        //            上面两行等价与下面这个
        std::unique_lock<std::mutex> lock(m_mutex);
        while (queue.empty())
        {
            notEmpty.wait(lock);
        }

        T front(std::move(queue.front()));
        queue.pop_front();
        return front;
    }

    size_t size() const
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        return queue.size();
    }

private:
    std::mutex m_mutex;
    std::condition_variable notEmpty;
    std::deque<T> queue;
};

#endif // BLOCKINGQUEUE_H
